package io.kiki.sba.registry.server.metadata.resource.filter;

import io.kiki.sba.registry.server.metadata.MetadataLeaderService;
import io.kiki.sba.registry.server.metadata.bootstrap.config.ServerConfig;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import javax.annotation.Priority;
import javax.ws.rs.Priorities;
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerRequestFilter;
import javax.ws.rs.core.Response;
import javax.ws.rs.ext.Provider;
import java.io.IOException;
import java.net.URI;


@Provider
@LeaderAwareRestController
@Priority(Priorities.USER)
public class LeaderAwareFilter implements ContainerRequestFilter {

    private static final Logger logger = LoggerFactory.getLogger(LeaderAwareFilter.class);

    @Autowired
    private MetadataLeaderService metadataLeaderService;

    @Autowired
    private ServerConfig serverConfig;

    public LeaderAwareFilter() {
    }

    public LeaderAwareFilter(MetadataLeaderService metadataLeaderService, ServerConfig serverConfig) {
        this.metadataLeaderService = metadataLeaderService;
        this.serverConfig = serverConfig;
    }

    @Override
    public void filter(ContainerRequestContext context) throws IOException {
        if (!metadataLeaderService.amILeader()) {
            Response response;
            String leaderIp = metadataLeaderService.getLeader();
            if (StringUtils.isEmpty(leaderIp)) {
                response = Response.status(Response.Status.BAD_REQUEST).header("reason", "no leader found").build();
            } else {
                try {
                    logger.warn("[filter]request: [{}][{}] need to redirect to {}", getRemoteIP(context), context.getMethod(), leaderIp);
                    response = Response.temporaryRedirect(new URI("http://" + leaderIp + ":" + serverConfig.getHttpServerPort() + "/" + context.getUriInfo().getPath())).build();
                } catch (Throwable e) {
                    logger.error("[filter]", e);
                    response = Response.status(Response.Status.INTERNAL_SERVER_ERROR).build();
                }
            }
            context.abortWith(response);
        }
    }

    public String getRemoteIP(ContainerRequestContext context) {
        String remote = context.getHeaderString("x-forwarded-for");
        if (StringUtils.isNotBlank(remote)) {
            return remote;
        }
        return "unknown";
    }


    protected LeaderAwareFilter setMetaLeaderService(MetadataLeaderService metadataLeaderService) {
        this.metadataLeaderService = metadataLeaderService;
        return this;
    }
}
